package com.solo.system.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.NumberUtil;
import com.solo.common.core.base.service.impl.BasicServiceImpl;
import com.solo.common.core.utils.NumberUtils;
import com.solo.common.core.utils.TreeUtils;
import com.solo.common.redis.utils.CacheUtils;
import com.solo.system.api.consts.SystemCacheKey;
import com.solo.system.api.entity.SysDept;
import com.solo.system.mapper.SysDeptMapper;
import com.solo.system.service.SysDeptService;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.solo.common.core.utils.ServiceExceptionUtil.exception;
import static com.solo.system.api.consts.SystemCode.*;

/**
 * 部门Service实现类
 * @author 十一
 * @since 2023/08/31 10:36
 * 人生若只如初见，何事秋风悲画扇
 **/
@Service
@AllArgsConstructor
public class SysDeptServiceImpl extends BasicServiceImpl<SysDeptMapper, SysDept> implements SysDeptService {
    
    private final SysDeptMapper sysDeptMapper;

    @Override
    public boolean create(SysDept entity) {
        // 验证部门代码是否唯一
        validateCodeUnique(entity.getCode(), null);
        // 验证父级部门有效性
        validateParentDept(entity.getParentId(), null);
        // 保存部门
        return super.save(entity);
    }

    @Override
    @CacheEvict(value = SystemCacheKey.DEPT, key = "#deptId")
    public boolean delete(Long deptId) {
        // 验证部门是否存在
        validateExists(deptId);
        // 验证子部门是否存在
        validateChildrenExists(deptId);
        // 删除部门
        return super.removeById(deptId);
    }

    @Override
    @CacheEvict(value = SystemCacheKey.DEPT, key = "#entity.deptId")
    public boolean update(SysDept entity) {
        Long deptId = entity.getDeptId();
        // 验证部门是否存在
        validateExists(deptId);
        // 验证部门代码是否唯一
        validateCodeUnique(entity.getCode(), deptId);
        // 验证父级部门有效性
        validateParentDept(entity.getParentId(), deptId);
        // 修改部门
        return super.updateById(entity);
    }

    @Override
    public List<Tree<Long>> selectDeptTree() {
        List<SysDept> deptList = queryChain().list();
        List<TreeNode<Long>> collect = deptList.stream()
                .map(getNodeFunction())
                .collect(Collectors.toList());
        return TreeUtil.build(collect, 0L);
    }

    @Override
    public Set<Long> selectChildDeptIds(Long deptId, boolean includeCurrentNode) {
        List<Tree<Long>> trees = selectDeptTree();
        Tree<Long> node = TreeUtils.getNode(trees.getFirst(), deptId);
        List<Long> deptIds = TreeUtils.getChildrenIds(node, includeCurrentNode);
        return new HashSet<>(new HashSet<>(deptIds));
    }

    @Override
    public void refreshCache() {
        CacheUtils.clear(SystemCacheKey.DEPT);
        List<SysDept> deptList = queryChain().list();
        deptList.forEach(dept -> CacheUtils.put(SystemCacheKey.DEPT, dept.getDeptId(), dept));
    }

    /**
     * 构造部门树
     * @return 部门树
     */
    @NotNull
    private Function<SysDept, TreeNode<Long>> getNodeFunction() {
        return menu -> {
            TreeNode<Long> node = new TreeNode<>();
            node.setId(menu.getDeptId());
            node.setParentId(menu.getParentId());
            node.setName(menu.getName());
            node.setWeight(menu.getSort());
            return node;
        };
    }

    /**
     * 验证部门是否存在
     * @param deptId 部门id
     */
    void validateExists(Long deptId) {
        if (deptId == null) {
            return;
        }
        SysDept entity = mapper.selectOneById(deptId);
        if (entity == null) {
            throw exception(DEPT_NOT_EXISTS);
        }
    }

    /**
     * 验证部门代码是否唯一
     * @param code 代码
     * @param deptId 部门id
     */
    void validateCodeUnique(String code, Long deptId) {
        SysDept dept = sysDeptMapper.selectByCode(code);
        if (Objects.isNull(dept)) {
            return;
        }
        if (!NumberUtil.equals(dept.getDeptId(), deptId)) {
            throw exception(DEPT_CODE_EXISTS, code);
        }
    }

    /**
     * 验证父级部门有效性
     * @param parentId 父级id
     * @param deptId 当前部门id
     */
    void validateParentDept(Long parentId, Long deptId) {
        if (parentId == null) {
            return;
        }
        // 父级部门不存在
        SysDept patentDept = sysDeptMapper.selectOneById(parentId);
        if (Objects.isNull(patentDept)) {
            throw exception(DEPT_PARENT_DEPT_EXISTS);
        }
        // 不能设置自己为父级部门
        if (Objects.equals(deptId, parentId)) {
            throw exception(DEPT_PARENT_DEPT_CANT_SET_OWN);
        }
        // 不能设置子部门为父级部门
        Set<Long> deptIds = selectChildDeptIds(deptId, false);
        if (deptIds.contains(parentId)) {
            throw exception(DEPT_PARENT_DEPT_CANT_SET_CHILDREN);
        }
    }

    /**
     * 验证子部门是否存在
     * @param deptId 部门id
     */
    void validateChildrenExists(Long deptId) {
        long count = sysDeptMapper.selectByParentId(deptId);
        if (NumberUtils.isPositiveInteger(count)) {
            throw exception(DEPT_EXISTS_CHILDREN);
        }
    }

}
